
#include "upgrade_cfg.h"

#if 1 == UPGRADE_DOUBLE_FLASH_MODE

#include <stdint.h>
#include <string.h>
#include "upgrade_double_flash.h"

enum {
    DOUBLE_FLASH_APP_1 = 0, // 第一个APP程序
    DOUBLE_FLASH_APP_2,     // 第二个APP程序
};

#endif

#if 1 == UPGRADE_DOUBLE_FLASH_MODE && 1 == BOOTLOADER

// 全局bootloader句柄
static Bootloader_t g_bootloader;

Upgrade_Ret_t 
bootloader_init(Bootloader_t* pstBootloader){

    // 输入参数判断
    if(NULL == pstBootloader || 
        NULL == pstBootloader->HW.pfnJumpTo || 
        NULL == pstBootloader->HW.pfnInfoWrite || 
        NULL == pstBootloader->HW.pfnInfoRead) return UPGRADE_RET_ERR;

    // 初始化bootloader的硬件接口
    g_bootloader.HW.pfnJumpTo = pstBootloader->HW.pfnJumpTo;
    g_bootloader.HW.pfnInfoWrite = pstBootloader->HW.pfnInfoWrite;
    g_bootloader.HW.pfnInfoRead = pstBootloader->HW.pfnInfoRead;

    // 初始化bootloader的软件接口
    memset(&g_bootloader.SW.stInfo, 0, sizeof(Upgrade_Info_t));
    g_bootloader.SW.u8Reserved  = 0;
    g_bootloader.SW.u16Reserved = 0;

    // 初始化成功
    g_bootloader.SW.u8Init = 1;

    // 返回成功
    return UPGRADE_RET_OK;
}

Upgrade_Ret_t
Bootloader_run(void){

    uint8_t u8Ret = 0;

    // 是否已经初始化
    if(0 == g_bootloader.SW.u8Init) return UPGRADE_RET_ERR;

    // 读取flash信息
    uint8_t* pu8Infoinfo = (uint8_t*)&g_bootloader.SW.stInfo;
    u8Ret = g_bootloader.HW.pfnInfoRead(INFO_ADDRESS, pu8Infoinfo, sizeof(Upgrade_Info_t));
    if(0 != u8Ret) return UPGRADE_RET_ERR;

    // 判断是否需要升级
    if(1 == g_bootloader.SW.stInfo.u8NeedUpgrade) {

        // 升级程序
        // 修改APP标志位
        g_bootloader.SW.stInfo.u8CurApp = !g_bootloader.SW.stInfo.u8CurApp;
        g_bootloader.SW.stInfo.u8NeedUpgrade = 0;

        // 保存flash信息
        u8Ret = g_bootloader.HW.pfnInfoWrite(INFO_ADDRESS, pu8Infoinfo, sizeof(Upgrade_Info_t));
        
        // 写入失败，返回上一次的APP程序
        if(0 != u8Ret) g_bootloader.SW.stInfo.u8CurApp = !g_bootloader.SW.stInfo.u8CurApp;
    }

    else if(0xFF == g_bootloader.SW.stInfo.u8NeedUpgrade) {
        
        // 信息区域被擦除，需要重新烧写信息 -- 默认启动第一个APP程序 -- 一般在首次烧写时使用
        g_bootloader.SW.stInfo.u8CurApp = DOUBLE_FLASH_APP_1;
        g_bootloader.SW.stInfo.u8NeedUpgrade = 0;

        // 保存flash信息
        u8Ret = g_bootloader.HW.pfnInfoWrite(INFO_ADDRESS, pu8Infoinfo, sizeof(Upgrade_Info_t));
    }

    // 跳转到对应APP程序
    uint32_t u32JumpAddr = (DOUBLE_FLASH_APP_1 == g_bootloader.SW.stInfo.u8CurApp) ? APP_ADDRESS_START : APP_ADDRESS_START2;

    // 跳转
    g_bootloader.HW.pfnJumpTo(u32JumpAddr);

    // 返回成功
    return UPGRADE_RET_OK;
}

#endif

#if 1 == UPGRADE_DOUBLE_FLASH_MODE && 1 == UPGRADE_APP

// 全局app句柄
static UpgradeApp_t g_upgradeApp;

Upgrade_Ret_t 
upgrade_app_init(UpgradeApp_t* pstUpgradeApp){

    // 输入参数判断
    if(NULL == pstUpgradeApp || 
        NULL == pstUpgradeApp->HW.pfnRestart || 
        NULL == pstUpgradeApp->HW.pfnInfoWrite || 
        NULL == pstUpgradeApp->HW.pfnInfoRead ||
        NULL == pstUpgradeApp->HW.pfnDataWrite) return UPGRADE_RET_ERR;

    // 初始化upgradeApp的硬件接口
    g_upgradeApp.HW.pfnRestart = pstUpgradeApp->HW.pfnRestart;
    g_upgradeApp.HW.pfnInfoWrite = pstUpgradeApp->HW.pfnInfoWrite;
    g_upgradeApp.HW.pfnInfoRead = pstUpgradeApp->HW.pfnInfoRead;
    g_upgradeApp.HW.pfnDataWrite = pstUpgradeApp->HW.pfnDataWrite;

    // 初始化upgradeApp的软件接口
    memset(&g_upgradeApp.SW.stInfo, 0, sizeof(Upgrade_Info_t));
    g_upgradeApp.SW.u32FWAddr   = 0;
    g_upgradeApp.SW.u8Init      = 0;
    g_upgradeApp.SW.u8Reserved  = 0;
    g_upgradeApp.SW.u16Reserved = 0;

    // 初始化成功
    g_upgradeApp.SW.u8Init = 1;

    // 返回成功
    return UPGRADE_RET_OK;
}

Upgrade_Ret_t
upgrade_app_run(void){

    uint8_t u8Ret = 0;

    // 是否已经初始化
    if(0 == g_upgradeApp.SW.u8Init) return UPGRADE_RET_ERR;

    // 读取flash信息
    uint8_t* pu8Infoinfo = (uint8_t*)&g_upgradeApp.SW.stInfo;
    u8Ret = g_upgradeApp.HW.pfnInfoRead(INFO_ADDRESS, pu8Infoinfo, sizeof(Upgrade_Info_t));
    if(0 != u8Ret) return UPGRADE_RET_ERR;

    // 升级标志置位 -- 通知bootloader进行升级
    g_upgradeApp.SW.stInfo.u8NeedUpgrade = 1;

    // 保存flash信息
    u8Ret = g_upgradeApp.HW.pfnInfoWrite(INFO_ADDRESS, pu8Infoinfo, sizeof(Upgrade_Info_t));
    if(0 != u8Ret) return UPGRADE_RET_ERR;

    // 重启
    g_upgradeApp.HW.pfnRestart();

    // 返回成功
    return UPGRADE_RET_OK;
}

Upgrade_Ret_t
upgrade_app_save(uint8_t* pu8Data, uint32_t u32Len){

    uint8_t u8Ret = 0;
    // 是否已经初始化
    if(0 == g_upgradeApp.SW.u8Init) return UPGRADE_RET_ERR;

    // 读取flash信息
    uint8_t* pu8Infoinfo = (uint8_t*)&g_upgradeApp.SW.stInfo;
    u8Ret = g_upgradeApp.HW.pfnInfoRead(INFO_ADDRESS, pu8Infoinfo, sizeof(Upgrade_Info_t));
    if(0 != u8Ret) return UPGRADE_RET_ERR;

    // 初次写写入固件包数据
    if(g_upgradeApp.SW.u32FWAddr == 0) {

        // 获取写入的区域
        uint32_t u32Addr = (DOUBLE_FLASH_APP_1 == g_upgradeApp.SW.stInfo.u8CurApp) ? 
        APP_ADDRESS_START2 : 
        APP_ADDRESS_START;

        // 更新固件地址
        g_upgradeApp.SW.u32FWAddr = u32Addr;
    }

    // 保存固件数据到flash
    u8Ret = g_upgradeApp.HW.pfnDataWrite(g_upgradeApp.SW.u32FWAddr, pu8Data, u32Len);
    g_upgradeApp.SW.u32FWAddr += u32Len;
    if(0 != u8Ret) {
        // 写入失败，重置固件地址 -- 重新烧写
        g_upgradeApp.SW.u32FWAddr = 0;
        return UPGRADE_RET_ERR;
    }

    // 返回成功
    return UPGRADE_RET_OK;
}

#endif
